/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

XiaoNuo采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改XiaoNuo源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/xiaonuo-vue
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/xiaonuo-vue
6.若您的项目无法满足以上几点，可申请商业授权，获取XiaoNuo商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package com.cn.xiaonuo.tcrfinance.fileupload.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cn.xiaonuo.common.entity.BusinessMessage;
import com.cn.xiaonuo.common.utils.FileUtil;
import com.cn.xiaonuo.common.utils.QiniuUtil;
import com.cn.xiaonuo.core.exception.ServiceException;
import com.cn.xiaonuo.core.factory.PageFactory;
import com.cn.xiaonuo.core.pojo.page.PageResult;
import com.cn.xiaonuo.tcrfinance.fileupload.entity.FileInfo;
import com.cn.xiaonuo.tcrfinance.fileupload.enums.FileInfoExceptionEnum;
import com.cn.xiaonuo.tcrfinance.fileupload.mapper.FileInfoMapper;
import com.cn.xiaonuo.tcrfinance.fileupload.param.FileInfoParam;
import com.cn.xiaonuo.tcrfinance.fileupload.service.FileInfoService;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FileUtils;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.util.*;

/**
 * 文件上传下载service接口实现类
 *
 * @author luyangyang
 * @date 2021-10-27 10:42:51
 */
@Service
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements FileInfoService {

    @Resource
    private FileInfoMapper fileInfoMapper;

    private static List<String> IMAGE_TYPE_ARRAY = Arrays.asList("image/bmp", "image/jpg", "image/jpeg", "image/png");

    @Override
    public PageResult<FileInfo> page(FileInfoParam fileInfoParam) {
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(fileInfoParam)) {

            // 根据唯一标识符 查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getId())) {
                queryWrapper.lambda().eq(FileInfo::getId, fileInfoParam.getId());
            }

            // 根据原始文件名 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getSourceName())) {
                queryWrapper.lambda().like(FileInfo::getSourceName, fileInfoParam.getSourceName());
            }

            // 根据目标文件名 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getTargetName())) {
                queryWrapper.lambda().like(FileInfo::getTargetName, fileInfoParam.getTargetName());
            }

            // 根据文件类型 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getContentType())) {
                queryWrapper.lambda().like(FileInfo::getContentType, fileInfoParam.getContentType());
            }

            // 根据文件大小 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getSize())) {
                queryWrapper.lambda().like(FileInfo::getSize, fileInfoParam.getSize());
            }

            // 根据文件路径 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getPath())) {
                queryWrapper.lambda().like(FileInfo::getPath, fileInfoParam.getPath());
            }

            // 根据文件md5加密 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getMd5())) {
                queryWrapper.lambda().like(FileInfo::getMd5, fileInfoParam.getMd5());
            }

            // 根据图片宽度 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getWidth())) {
                queryWrapper.lambda().like(FileInfo::getWidth, fileInfoParam.getWidth());
            }

            // 根据图片高度 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getHeight())) {
                queryWrapper.lambda().like(FileInfo::getHeight, fileInfoParam.getHeight());
            }

            // 根据创建时间 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getCreatedAt())) {
                queryWrapper.lambda().like(FileInfo::getCreatedAt, fileInfoParam.getCreatedAt());
            }

            // 根据最后更新时间 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getUpdatedAt())) {
                queryWrapper.lambda().like(FileInfo::getUpdatedAt, fileInfoParam.getUpdatedAt());
            }

        }
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public List<FileInfo> list(FileInfoParam fileInfoParam) {
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotNull(fileInfoParam)) {

            // 根据唯一标识符 查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getId())) {
                queryWrapper.eq(FileInfo::getId, fileInfoParam.getId());
            }

            // 根据原始文件名 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getSourceName())) {
                queryWrapper.like(FileInfo::getSourceName, fileInfoParam.getSourceName());
            }

            // 根据目标文件名 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getTargetName())) {
                queryWrapper.like(FileInfo::getTargetName, fileInfoParam.getTargetName());
            }

            // 根据文件类型 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getContentType())) {
                queryWrapper.like(FileInfo::getContentType, fileInfoParam.getContentType());
            }

            // 根据文件大小 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getSize())) {
                queryWrapper.like(FileInfo::getSize, fileInfoParam.getSize());
            }

            // 根据文件路径 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getPath())) {
                queryWrapper.like(FileInfo::getPath, fileInfoParam.getPath());
            }

            // 根据文件md5加密 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getMd5())) {
                queryWrapper.like(FileInfo::getMd5, fileInfoParam.getMd5());
            }

            // 根据图片宽度 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getWidth())) {
                queryWrapper.like(FileInfo::getWidth, fileInfoParam.getWidth());
            }

            // 根据图片高度 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getHeight())) {
                queryWrapper.like(FileInfo::getHeight, fileInfoParam.getHeight());
            }

            // 根据创建时间 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getCreatedAt())) {
                queryWrapper.like(FileInfo::getCreatedAt, fileInfoParam.getCreatedAt());
            }

            // 根据最后更新时间 模糊查询
            if (ObjectUtil.isNotEmpty(fileInfoParam.getUpdatedAt())) {
                queryWrapper.like(FileInfo::getUpdatedAt, fileInfoParam.getUpdatedAt());
            }

        }
        return this.list(queryWrapper);
    }

    @Override
    public void add(FileInfoParam fileInfoParam) {
        FileInfo fileInfo = new FileInfo();
        BeanUtil.copyProperties(fileInfoParam, fileInfo);
        this.save(fileInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(FileInfoParam fileInfoParam) {
            this.removeById(fileInfoParam.getId());
                                                }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(FileInfoParam fileInfoParam) {
        FileInfo fileInfo = this.queryFileInfo(fileInfoParam);
        BeanUtil.copyProperties(fileInfoParam, fileInfo);
        this.updateById(fileInfo);
    }

    @Override
    public FileInfo detail(FileInfoParam fileInfoParam) {
        return this.queryFileInfo(fileInfoParam);
    }

    /**
     * 获取文件上传下载
     *
     * @author luyangyang
     * @date 2021-10-27 10:42:51
     */
    private FileInfo queryFileInfo(FileInfoParam fileInfoParam) {
            FileInfo fileInfo = this.getById(fileInfoParam.getId());
                                                    if (ObjectUtil.isNull(fileInfo)) {
            throw new ServiceException(FileInfoExceptionEnum.NOT_EXIST);
        }
        return fileInfo;
    }

    public static FileInfo getFileInfo(MultipartFile file) throws Exception {
        String md5 = FileUtil.fileMd5(file.getInputStream());
        FileInfo fileInfo = new FileInfo();
        fileInfo.setMd5(md5);// 将文件的md5设置为文件表的id
        fileInfo.setSourceName(file.getOriginalFilename());
        fileInfo.setContentType(file.getContentType());
        fileInfo.setSize(file.getSize());
        fileInfo.setCreatedAt(new Timestamp(new Date().getTime()));
        return fileInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadFile(MultipartFile file) {
        String fileUrl="";
        try {
            FileInfo fileInfo = getFileInfo(file);
            FileInfo slFileInfo = fileInfoMapper.selectFileInfo(fileInfo.getMd5());
            if(null!=slFileInfo){
                fileUrl=slFileInfo.getPath();
                return fileUrl;
            }
            fileUrl= QiniuUtil.uploadFileData(file);
            fileInfo.setPath(fileUrl);
            fileInfoMapper.addFileInfo(fileInfo);
        }catch (Exception e){
            e.printStackTrace();
        }
        return fileUrl;
    }

    /**
     * 上传文件，并返回图片URL、图片名称和图片的宽度和高度
     *
     * @param file 文件
     * @return 文件URL、图片宽度、高度
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> newUpload(MultipartFile file) {
        String fileUrl="";
        Map<String, Object> map = new HashMap<>();
        try {
            FileInfo fileInfo = getFileInfo(file);
            FileInfo slFileInfo = fileInfoMapper.selectFileInfo(fileInfo.getMd5());
            if(null!=slFileInfo){
                fileUrl=slFileInfo.getPath();
                map.put("fileUrl",fileUrl);
                return map;
            }
            fileUrl=QiniuUtil.uploadFile(file);
            map.put("fileUrl",fileUrl);
            fileInfo.setPath(fileUrl);
            fileInfoMapper.addFileInfo(fileInfo);
        }catch (Exception e){
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 下载文件
     *
     * @param name   文件名称
     * @param width  图片宽度
     * @param height 图片高度
     * @return 文件字节集合
     */
    @Override
    public ResponseEntity<byte[]> download(String name, Integer width, Integer height) {
        try {
            FileInfo fileInfo = this.fileInfoMapper.selectFileInfo(name);
            byte[] bytes;
            if (IMAGE_TYPE_ARRAY.contains(fileInfo.getContentType())) {
                if (null != width && null != height) {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    Thumbnails.of(Paths.get(fileInfo.getPath()).toFile()).size(width, height).toOutputStream(baos);
                    bytes = baos.toByteArray();
                } else {
                    bytes = FileUtils.readFileToByteArray(new File(fileInfo.getPath()));
                }
            } else {
                bytes = FileUtils.readFileToByteArray(new File(fileInfo.getPath()));
            }

            // 解决中文文件名乱码关键行
            String fileName = URLEncoder.encode(fileInfo.getSourceName(), StandardCharsets.UTF_8.toString());

            return ResponseEntity.ok()
                    .contentType(MediaType.parseMediaType(fileInfo.getContentType()))
                    .contentLength(bytes.length)
                    .header("Content-Disposition", "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName)
                    .body(bytes);
        } catch (IOException e) {
            log.error("下载文件失败，{}", e);
        }
        return null;
    }
    @Override
    public BusinessMessage uploadshopimg(List<MultipartFile> files) {
        BusinessMessage message = new BusinessMessage();
        List<Map<String, Object>> array = new ArrayList<>();
        for (MultipartFile file : files) {
            Map<String, Object> url = this.newUpload(file);
            array.add(url);
        }
        if(array != null && array.size() > 0){
            message.setData(array);
            message.setMessage("上传图片成功");
            message.setSuccess(true);
            return message;
        }else {
            message.setSuccess(false);
            message.setMessage("上传图片失败");
        return message;
        }
    }
}
